// *************************************************************************************************
//
// MK3D Engine
// --------------------------------------
// Copyright (C) 2007-2011 Zeb (mailto: zebbey@gmail.com)
//
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// *************************************************************************************************

#include "mk_header.h"
#include "mk_terrain_height_brush.h"
#include "mk_mesh.h"
#include "mk_image.h"
#include "mk_error.h"
#include "mk_resource_manager.h"
#include "mk_engine.h"
#include "mk_painter.h"
#include "mk_entity_terrain.h"

namespace MK3DE
{
	CTerrainHeightBrush::CTerrainHeightBrush()
	{
		_size = 500.0f;
		_powerOffset = 0;
		_powerFactor = 1.0f;
		_x = 0;
		_y = 0;
		_brushImage = NULL;
		_bPaintUp = TRUE;
	}

	CTerrainHeightBrush::~CTerrainHeightBrush()
	{
		SAFE_RELEASE(_brushImage);
	}

	void CTerrainHeightBrush::Paint(CTerrainRegion::TerrainData& terrainData)
	{
		if (!_brushImage)
			return;

		float half = _size * 0.5f;
		float left = _x - half;
		float top = _y - half;

		BYTE* imageData = _brushImage->GetData();
		DWORD width = _brushImage->GetWidth();
		DWORD height = _brushImage->GetHeight();
		ASSERT(imageData);
		ASSERT(width);
		ASSERT(height);

		std::vector<CMesh::Position>::iterator i = terrainData.vecPosition.begin();
		while (i != terrainData.vecPosition.end())
		{
			D3DXVECTOR3& pos = *i;
			float dx = pos.x - left;
			float dy = pos.z - top;
			if (dx > 0 && dx < _size && dy > 0 && dy < _size)
			{
				float tu = dx / _size;
				float tv = dy / _size;

				DWORD imageX = (DWORD)(tu * (float)width + 0.5f);
				DWORD imageY = (DWORD)(tv * (float)height + 0.5f);
				if (imageX < width && imageY < height)
				{
					BYTE pixelData = imageData[imageY * height + imageX];
					if (_powerOffset > MK_EPSILON)
					{
						float power = (float)pixelData * _powerFactor + _powerOffset;
						pos.y = power;
					}
					else
					{
						float power = (float)pixelData * _powerFactor;
						if (_bPaintUp)
							pos.y += power;
						else
							pos.y -= power;
					}
				}
			}

			++i;
		}
	}

	void CTerrainHeightBrush::Render(CEntityTerrain* terrain)
	{
		CPainter* painter = GetEngine()->GetPainter();
		float left = _x - _size * 0.5f;
		float right = _x + _size * 0.5f;
		float top = _y - _size * 0.5f;
		float bottom = _y + _size * 0.5f;

		// draw up line.
		float x1 = left;
		float z1 = top;
		while (true)
		{
			float x2 = x1 + 20.0f;
			float z2 = top;
			float y1 = 0, y2 = 0;
			BOOL end = FALSE;
			if (x2 > right - MK_EPSILON)
			{
				x2 = right;
				end = TRUE;
			}

			terrain->GetGroundHeight(y1, x1, z1);
			terrain->GetGroundHeight(y2, x2, z2);
			painter->DrawLine3D(D3DXVECTOR3(x1, y1 + 5.0f, z1), D3DXVECTOR3(x2, y2 + 5.0f, z2), 0xffffffff, 0xffffffff);

			if (end)
				break;

			x1 = x2;
		}

		// draw left line.
		x1 = left;
		z1 = top;
		while (true)
		{
			float x2 = x1;
			float z2 = z1 + 20.0f;
			float y1 = 0, y2 = 0;
			BOOL end = FALSE;
			if (z2 > bottom - MK_EPSILON)
			{
				z2 = bottom;
				end = TRUE;
			}

			terrain->GetGroundHeight(y1, x1, z1);
			terrain->GetGroundHeight(y2, x2, z2);
			painter->DrawLine3D(D3DXVECTOR3(x1, y1 + 5.0f, z1), D3DXVECTOR3(x2, y2 + 5.0f, z2), 0xffffffff, 0xffffffff);

			if (end)
				break;

			z1 = z2;
		}

		// draw right line.
		x1 = right;
		z1 = top;
		while (true)
		{
			float x2 = x1;
			float z2 = z1 + 20.0f;
			float y1 = 0, y2 = 0;
			BOOL end = FALSE;
			if (z2 > bottom - MK_EPSILON)
			{
				z2 = bottom;
				end = TRUE;
			}

			terrain->GetGroundHeight(y1, x1, z1);
			terrain->GetGroundHeight(y2, x2, z2);
			painter->DrawLine3D(D3DXVECTOR3(x1, y1 + 5.0f, z1), D3DXVECTOR3(x2, y2 + 5.0f, z2), 0xffffffff, 0xffffffff);

			if (end)
				break;

			z1 = z2;
		}

		// draw bottom line.
		x1 = left;
		z1 = bottom;
		while (true)
		{
			float x2 = x1 + 20.0f;
			float z2 = bottom;
			float y1 = 0, y2 = 0;
			BOOL end = FALSE;
			if (x2 > right - MK_EPSILON)
			{
				x2 = right;
				end = TRUE;
			}

			terrain->GetGroundHeight(y1, x1, z1);
			terrain->GetGroundHeight(y2, x2, z2);
			painter->DrawLine3D(D3DXVECTOR3(x1, y1 + 5.0f, z1), D3DXVECTOR3(x2, y2 + 5.0f, z2), 0xffffffff, 0xffffffff);

			if (end)
				break;

			x1 = x2;
		}
	}

	BOOL CTerrainHeightBrush::LoadImage(const char* fileName, DWORD width, DWORD height)
	{
		BOOL ret = FALSE;
		CResourceManager* resourceManger = GetEngine()->GetResourceManager();
		ret = resourceManger->GetImage(fileName, _brushImage);
		MK_PROCESS_ERROR(ret);

		ret = _brushImage->ConvertFormat(PF_L8);
		MK_PROCESS_ERROR(ret);

		ret = TRUE;
Exit0:
		return ret;
	}
}